"""
签名工具
"""
import base64
import hashlib
import hmac


class util(object):
    # Http头是否参与签名 return
    def isHeaderToSign(self, headerName: str, signHeaderPrefixList: list):
        if (len(headerName) == 0):
            return False
        if (headerName.startswith("X-Ca-Signature")):
            return False
        if (headerName.startswith("X-Ca-Signature-Headers")):
            return False
        if (headerName.startswith("X-Ca-")):
            return True

        if not signHeaderPrefixList:
            i = 0
            while i < len(signHeaderPrefixList):
                if (headerName.lower() == signHeaderPrefixList[i]):
                    return True
        return False

    # 构建待签名Http头
    '''
    headers 请求中所有的Http头
    signHeaderPrefixList 自定义参与签名Header前缀
    return 待签名Http头
    '''

    def buildHeaders(self, headers: dict, signHeaderPrefixList: list):
        sb = ""

        if signHeaderPrefixList:
            signHeaderPrefixList = []
            if "X-Ca-Signature" in signHeaderPrefixList:
                signHeaderPrefixList.remove("X-Ca-Signature")
            if "Accept" in signHeaderPrefixList:
                signHeaderPrefixList.remove("Accept")
            if "Content-MD5" in signHeaderPrefixList:
                signHeaderPrefixList.remove("Content-MD5")
            if "Content-Type" in signHeaderPrefixList:
                signHeaderPrefixList.remove("Content-Type")
            if "Date" in signHeaderPrefixList:
                signHeaderPrefixList.remove("Date")
            signHeaderPrefixList.sort()
            if (headers is not None):
                sortMap = headers
                st = ""
                for key, value in sortMap.items():
                    if (self.isHeaderToSign(key, signHeaderPrefixList)):
                        sb = sb + key
                        sb = sb + ":"
                        if (value is not None):
                            sb = sb + value
                        sb = sb + "\n"
                    if (len(st) > 0):
                        st = st + ","
                    st = st + key
                headers["X-Ca-Signature-Headers"] = str(st)
                # headers.update("X-Ca-Signature-Headers", str(st))
        return str(sb)

    '''
    *构建待签名Path + Query + BODY
    *
    * @ param  path
    * @ param  querys
    * @ param  bodys
    * @ return 待签名
    '''

    def buildResource(self, path: str, querys: dict, bodys: dict):
        sb = ''
        if (len(path) != 0):
            sb = sb + path
        sortMap = {}
        if (bool(querys) & len(querys.keys()) > 0):
            for key, value in querys.items():
                if key != '':
                    sortMap.setdefault(key, value)

        if (bool(bodys) & len(bodys.keys()) > 0):
            for key, value in bodys.items():
                if key != '':
                    sortMap.setdefault(key, value)

        sbParam = ''
        for key, value in sortMap.items():
            if key != '':
                if len(sbParam) > 0:
                    sbParam = sbParam + ":"
                sbParam = sbParam + key
                if value != '':
                    sbParam = sbParam + "=" + value

        if (len(sbParam) > 0):
            sb = sb + "?"
            sb = sb + sbParam
        # print(sb)
        return sb

    '''
    建待签名字符串
    '''

    def buildStringToSign(self, method: str, path: str, headers: dict, querys: dict, bodys: dict,
                          signHeaderPrefixList: list):
        sb = ""
        sb = sb + method.upper() + '\n'
        if headers:
            if "Accept" in headers.keys():
                if headers["Accept"]:
                    sb = sb + headers["Accept"]
            sb = sb + "\n"

            if "Content-MD5" in headers.keys():
                if headers["Content-MD5"]:
                    sb = sb + headers["Content-MD5"]
            sb = sb + "\n"

            if "Content-Type" in headers.keys():
                if headers["Content-Type"]:
                    sb = sb + headers["Content-Type"]
            sb = sb + "\n"

            if "Date" in headers.keys():
                if headers["Date"]:
                    sb = sb + headers["Date"]
        sb = sb + "\n"
        sb = sb + self.buildHeaders(headers, signHeaderPrefixList)
        sb = sb + self.buildResource(path, querys, bodys)
        print(sb)
        return sb

    '''
    计算签名
    '''

    def sign(self, secret: str, method: str, path: str, headers: dict, querys: dict, bodys: dict,
             signHeaderPrefixList: list) -> object:
        s = self.buildStringToSign(method, path, headers, querys, bodys, signHeaderPrefixList)
        message = bytes(s, encoding='utf-8')
        secret = bytes(secret, encoding='utf-8')
        signature = base64.b64encode(hmac.new(secret, message, digestmod=hashlib.sha256).digest())
        return signature


if __name__ == '__main__':
    # 校验GET
    a = util()
    s = a.sign(secret="098ff21c253241bf9ac9e2761782a318", method="POST",
               path="/open-product-service/api/official/function/generate",
               headers={"X-Ca-Key": "5c092a8201474bb0", "Accept": "application/json",
                        "X-Ca-Signature": "",
                        "Content-Type": "application/json"},
               querys={}, bodys={}, signHeaderPrefixList=[1])
    print(s)

